home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1996 #15
/
Monster Media Number 15 (Monster Media)(July 1996).ISO
/
math
/
hugemath.zip
/
HUGEMATH.C
< prev
next >
Wrap
C/C++ Source or Header
|
1996-04-06
|
35KB
|
1,412 lines
/*
HUGEMATH :
This program is basically a calculator which works with integers
These can be more or less as large as you want. The exe file supplied
has been compiled to accept integers up to about 500 digits each.
Some of the code may be difficult to read because it has been optimised
as far as possible. Many primality tests have also been implemented.
See the doc file for a description of usage.
This program was written by Paul Young, using Turbo C++.
I accept no responsibility for use or misuse of this program in any way.
This program is Public Domain.
It may be copied freely provided this notice is included.
This program may be used as a base or included in other programs
however these programs must also be Public Domain and no monetary gain
should be made from these. Help support Public Domain programming.
P Young, 101716.3323@compuserve.com
*/
/*
This program should be compiled with the smallest possible memory
model. This is so that it runs at the fastest speed possible, because
near pointers will be used. Unless anyone has a better idea.
Unfortunately it limits the size.
*/
#include <conio.h>;
#include <stdio.h>;
#include <stdlib.h>;
#include <string.h>;
#include <time.h>;
#define TRUE 1
#define FALSE 0
#define NIL 0
#define REG 1
#define CVALUE 2
#define NUM 3
#define TVAL 4
#define FVAL 5
#define QUIT 6
#define MAXLEN 120
#define NUM_SIEVEVALUES 20
/*
global variables
the regA,etc are registers for the calculator
they consist of reg[0] which indicates the length of data
and reg[1]..reg[length] which is lsb..msb of number.
Holding the length like this makes the program generally more
efficient. Fixed length numbers of 500 digits are s-l-o-w.
*/
unsigned int regA[2*MAXLEN+1];
unsigned int regB[2*MAXLEN+1];
unsigned int regC[2*MAXLEN+1];
unsigned int regD[2*MAXLEN+1];
typedef unsigned char bool;
unsigned int primes[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,
67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,
139,149,151,157,163,167,173,179,181,191,193,197,199,
211,223,227,229,233,239,241,251,0};
unsigned int sievevalue[NUM_SIEVEVALUES]={256,243,125,49,121,169,17,19,23,
29,31,37,41,43,47,53,59,61,67,71};
unsigned int sieves[256*NUM_SIEVEVALUES];
unsigned int modtable[NUM_SIEVEVALUES];
/*
prototypes for functions
*/
void hugeadd(unsigned int *reg1,unsigned int *reg2,bool checkoverflow);
void hugermul(unsigned int *reg1,unsigned int *reg2,bool checkoverflow);
void hugerdiv(unsigned int *reg1,unsigned int *reg2,bool divmod);
void hugepri(unsigned int *reg1,bool suppress);
void hugemod(unsigned int *reg1,unsigned int num,unsigned int *carry);
void hugeinc(unsigned int *reg1,bool checkoverflow);
void hugedec(unsigned int *reg1);
void hugeequ(unsigned int *reg1,unsigned int *reg2);
void hugemul2(unsigned int *reg1,bool checkoverflow);
void hugediv2(unsigned int *reg1,unsigned int *carry);
void hugersub(unsigned int *reg1,unsigned int *reg2);
void hugetdiv(unsigned int *reg1,int kvalue);
void repunit(unsigned int *reg1,unsigned int num);
void mersenne(unsigned int *reg1,unsigned int num);
void fibonacci(unsigned int *reg1,unsigned int num);
void factorise(unsigned int *reg1);
void hugeinp(unsigned int *reg1,char *buffer);
void hugeswap(unsigned int *reg1,unsigned int *reg2);
void hugepriregs(void);
void hugegcd(unsigned int *reg1,unsigned int *reg2);
void mprime(unsigned int *reg1,unsigned int num);
void hugeroot(unsigned int *reg1,unsigned int *reg2);
void psptest(unsigned int *reg1,unsigned int num);
void pollard(unsigned int *reg1,unsigned int num);
void sequence(unsigned int *reg1,unsigned int num);
void montecarlo(unsigned int *reg1,unsigned int num);
void autopsptest(unsigned int *reg1,unsigned int num);
void proveprime(unsigned int *reg1,unsigned int *reg2);
void findwitness(unsigned int *reg1,unsigned int *reg2);
void witness(unsigned int *reg1,unsigned int *reg2,unsigned int num);
void factorial(unsigned int *reg1,unsigned int num);
void power2(unsigned int *reg1,unsigned int num);
void pown(unsigned int *reg1,unsigned int num);
void fermatsieve(unsigned int *reg1);
/*
Here is the table of options available
*/
struct
{ char *cmd;
void (*fn)();
int arg1,
arg2,
arg3;
} comtable[]={ {"add",hugeadd,REG,CVALUE,TVAL},
{"div",hugerdiv,REG,CVALUE,TVAL},
{"mul",hugermul,REG,CVALUE,TVAL},
{"sub",hugersub,REG,CVALUE,NIL},
{"mod",hugerdiv,REG,CVALUE,FVAL},
{"priall",hugepriregs,NIL,NIL,NIL},
{"pri",hugepri,REG,NIL,FVAL},
{"inc",hugeinc,REG,NIL,TVAL},
{"dec",hugedec,REG,NIL,NIL},
{"equ",hugeequ,REG,CVALUE,NIL},
{"swap",hugeswap,REG,CVALUE,NIL},
{"mul2",hugemul2,REG,NIL,TVAL},
{"div2",hugediv2,REG,NIL,NIL},
{"rep",repunit,REG,NUM,NIL},
{"fib",fibonacci,REG,NUM,NIL},
{"smallfac",factorise,REG,NIL,NIL},
{"mer",mersenne,REG,NUM,NIL},
{"tdiv",hugetdiv,REG,NUM,NIL},
{"gcd",hugegcd,REG,CVALUE,NIL},
{"mprime",mprime,REG,NUM,NIL},
{"root",hugeroot,REG,CVALUE,NIL},
{"psp",psptest,REG,NUM,NIL},
{"pollard",pollard,REG,NUM,NIL},
{"autopsp",autopsptest,REG,NUM,NIL},
{"monte",montecarlo,REG,NUM,NIL},
{"sequence",sequence,REG,NUM,NIL},
{"findwitness",findwitness,REG,CVALUE,NIL},
{"proveprime",proveprime,REG,CVALUE,NIL},
{"2pow",power2,REG,NUM,NIL},
{"npow",pown,REG,NUM,NIL},
{"factorial",factorial,REG,NUM,NIL},
{"fermat",fermatsieve,REG,NIL,NIL},
{"quit",NULL,QUIT,NIL,NIL},
{NULL,NULL,NIL,NIL,NIL}
};
/*
sets all registers to zero
*/
void init(void)
{ regA[0]=0;
regB[0]=0;
regC[0]=0;
regD[0]=0;
}
/*
exits program on overflow.
you may want to change this to continue
*/
void overflow(int num)
{ printf("Overflow occurred at %d\n\r",num);
exit(1);
}
/*
adds two of the numbers together
this is complicated due to possible differing lengths of numbers
*/
void hugeadd(unsigned int *reg1,unsigned int *reg2,bool checkoverflow)
{ int len1=reg1[0],
len2=reg2[0];
register count;
unsigned long temp=0;
if (len2>len1) /* pad shortest with zeroes */
{ for (count=len1+1;count<=len2;count++) reg1[count]=0;
len1=len2;
}
else if (len2<len1) for (count=len2+1;count<=len1;count++) reg2[count]=0;
count=1;
while (len1--) /* now add them */
{ temp+=(long)reg1[count]+reg2[count];
reg1[count++]=temp;
temp>>=16;
}
if (!temp) reg1[0]=--count; /* and check length of result */
else if ((checkoverflow)&&(count>MAXLEN)) overflow(1);
else reg1[reg1[0]=count]=temp;
}
/*
simple division routine for reg by int
*/
void hugediv(unsigned int *reg1,unsigned int num,unsigned int *carry)
{ register len1=reg1[0];
unsigned long temp=0;
*carry=0;
if (!num) { overflow(2);
return;
}
while (len1)
{ temp=reg1[len1]+(((long)*carry)<<16);
*carry=temp%num;
reg1[len1--]=temp/num;
}
if (!reg1[reg1[0]]) reg1[0]--;
}
/*
simple multiply for reg by int
the checkoverflow variable is normally true however some
routines use intermediate values which may be larger than
the normal maximum. These have large temporary registers
and overflow will not occur
*/
void hugemul(unsigned int *reg1,unsigned int num,bool checkoverflow)
{ int len1=reg1[0],
count=1;
unsigned long temp=0;
while (len1--)
{ temp+=(long)num*reg1[count];
reg1[count++]=temp;
temp>>=16;
}
if (!temp) return;
if ((checkoverflow)&&(count>MAXLEN)) overflow(3);
reg1[reg1[0]=count]=temp;
}
/*
this prints a reg to the screen
*/
void hugepri(unsigned int *reg1,bool suppress)
{ unsigned int reg2[MAXLEN+1],
ch;
char buffer[5*MAXLEN+2];
register count;
for (count=0;count<=reg1[0];count++) reg2[count]=reg1[count];
if (!reg1[0]) { printf("0\n\r");
return;
}
count=0;
while (reg2[0])
{ hugediv(reg2,10,&ch);
buffer[count++]=ch+'0';
}
while (count) printf("%c",buffer[--count]);
if(!suppress)printf("\n\r");
}
/*
simple mod routine for reg mod int
*/
void hugemod(unsigned int *reg1,unsigned int num,unsigned int *carry)
{ register len1=reg1[0];
unsigned long temp=0;
*carry=0;
if (!num) { overflow(4);
return;
}
while (len1)
{ temp=reg1[len1--]+(((long)*carry)<<16);
*carry=temp%num;
}
}
/*
increments reg. Complicated again due to need to check for
length increase in reg.
*/
void hugeinc(unsigned int *reg1,bool checkoverflow)
{ int len1=reg1[0],
carry=1,
temp=1;
while (len1--)
{ reg1[temp]+=carry;
if (reg1[temp++]){ len1=0;
carry=0;
}
}
if (carry) if ((checkoverflow)&&(temp>MAXLEN)) overflow(5);
else reg1[reg1[0]=temp]=1;
}
/*
heres the corresponding decrement
*/
void hugedec(unsigned int *reg1)
{ int len1=reg1[0],
carry=1,
temp=1;
if (!len1) { overflow(6);
return;
}
while ((len1--)&&(carry))
{ reg1[temp]-=carry;
if (reg1[temp++]+1) carry=0;
}
if (!reg1[reg1[0]]) reg1[0]--;
}
/*
fast equal
*/
void hugeequ(unsigned int *reg1,unsigned int *reg2)
{ memmove(reg1,reg2,(reg2[0]+1)*sizeof(unsigned int));
}
/*
fast multiply by two using shifting
*/
void hugemul2(unsigned int *reg1,bool checkoverflow)
{ int len1=reg1[0];
register count=1;
unsigned long temp=0;
while(len1--)
{ temp+=(((long)reg1[count])<<1);
reg1[count++]=temp;
temp>>=16;
}
if(!temp)return;
if((checkoverflow)&&(count>MAXLEN))overflow(7);
reg1[reg1[0]=count]=1;
}
/*
fast div by two using shifting
*/
void hugediv2(unsigned int *reg1,unsigned int *carry)
{ register len1=reg1[0];
unsigned long temp=0;
*carry=0;
while(len1)
{ temp=reg1[len1]+(((long)*carry)<<16);
*carry=temp&1;
reg1[len1--]=temp>>1;
}
len1=reg1[0];
if(!len1)return;
if(!reg1[len1])reg1[0]--;
}
/*
multiplies two numbers together
each of large size
fairly simple stuff
*/
void hugermul(unsigned int *reg1,unsigned int *reg2,bool checkoverflow)
{ unsigned int result[2*MAXLEN+1];
int len2=reg2[0],
mult;
register count;
if((!len2)||(!reg1[0])) { reg1[0]=0;
return;
}
result[0]=0;
while(len2)
{ mult=reg2[len2--];
for(count=0;count<16;count++)
{ hugemul2(result,checkoverflow);
if(mult&32768)hugeadd(result,reg1,checkoverflow);
mult<<=1;
}
}
hugeequ(reg1,result);
}
/*
subtracts two large numbers
careful with result length.
*/
void hugersub(unsigned int *reg1,unsigned int *reg2)
{ int len1=reg1[0],
len2=reg2[0],
carry=0;
register count=1;
unsigned long temp=0;
if(len2>len1){ overflow(8);
return;
}
while(len2--)
{ temp=(long)reg1[count]-reg2[count]-carry;
reg1[count++]=temp;
carry=(temp>>16)&1;
len1--;
}
while((len1--)&&(carry)) if(reg1[count++]--)carry=0;
while((reg1[0])&&(!reg1[reg1[0]]))reg1[0]--;
if(carry)overflow(9);
}
/*
adds int to reg the quick way
*/
void hugeaddnum(unsigned int *reg1,unsigned int value,bool checkoverflow)
{ unsigned int tmp[2*MAXLEN+1];
if(!value)return;
tmp[0]=1;
tmp[1]=value;
hugeadd(reg1,tmp,checkoverflow);
}
/*
divides one reg by another
fairly quick
this seems to be the one most people avoid
fairly straightforward if you can think in binary
*/
void hugerdiv(unsigned int *reg1,unsigned int *reg2,bool divmod)
{ unsigned int result[2*MAXLEN+1],
carry;
int count=0;
register len1=reg1[0];
bool greater;
if(!reg2[0]){ overflow(10);
return;
}
while((reg2[0]<len1)||((reg2[0]==len1)&&(reg2[reg2[0]]<reg1[len1])))
{ hugemul2(reg2,FALSE);
count++;
}
result[0]=0;
do
{ if(reg1[0]>reg2[0])greater=TRUE;
else
if(reg2[0]>reg1[0])greater=FALSE;
else
{ greater=TRUE;
len1=reg1[0];
do greater=!(reg1[len1]<reg2[len1--]);
while((greater)&&(reg1[len1+1]==reg2[len1+1])&&(len1));
}
if (greater) { hugersub(reg1,reg2);
hugeinc(result,FALSE);
}
if (count) { hugediv2(reg2,&carry);
hugemul2(result,FALSE);
}
} while(count--);
if (divmod) hugeequ(reg1,result);
}
/*
used by trial division
*/
void hugecheckb(unsigned int *testval,unsigned int *reg1)
{ unsigned int modres[MAXLEN+1],
count=0,
carry;
int i=1;
bool fin;
while(primes[i])
{ hugemod(testval,primes[i++],&carry);
if(!carry)return;
}
do
{ hugeequ(modres,reg1);
hugerdiv(modres,testval,fin=FALSE);
if(!modres[0]) { hugerdiv(reg1,testval,fin=TRUE);
count++;
}
} while(fin);
if(count) { printf("Factor : ");
hugepri(testval,TRUE);
if(count>1)printf(" ^ %u",count);
printf("\n\r");
}
}
/*
also used by trial division
tests numbers of the form
6n-1,6n+1
*/
void hugechecka(unsigned int *testval,unsigned int *reg1)
{ hugedec(testval);
hugecheckb(testval,reg1);
hugeaddnum(testval,2,TRUE);
hugecheckb(testval,reg1);
hugedec(testval);
}
/*
heres the trial division
starts at 65536 - see factor which finds small factors quickly
use only if really stuck in factoring or you know a special
property - for example factors are of form 1024k+-1
*/
void hugetdiv(unsigned int *reg1,int kvalue)
{ unsigned int testval[MAXLEN+1],
squareval[MAXLEN+1],
calcval,
len1;
bool greater;
calcval=(int)((long)65536L/kvalue)*kvalue;
testval[0]=1;
testval[1]=calcval;
do
{ hugeaddnum(testval,kvalue,TRUE);
hugechecka(testval,reg1);
hugeequ(squareval,testval);
hugermul(squareval,testval,TRUE);
if(kbhit()){ hugepri(testval,FALSE);
if(getch()=='e')return;
}
len1=squareval[0];
if(len1>reg1[0])greater=TRUE;
else if(len1<reg1[0])greater=FALSE;
else
{ greater=TRUE;
do greater=!(squareval[len1]<reg1[len1--]);
while((greater)&&(squareval[len1+1]==reg1[len1+1])&&(len1));
}
if(greater) { printf("Factor : ");
hugepri(reg1,FALSE);
printf("Factored\n");
}
} while(!greater);
}
/*
calculates repunit
*/
void repunit(unsigned int *reg1,unsigned int num)
{ reg1[0]=0;
while (num--)
{ hugemul(reg1,10,TRUE);
hugeinc(reg1,TRUE);
}
}
/*
calculates mersenne number
*/
void mersenne(unsigned int *reg1,unsigned int num)
{ reg1[0]=0;
while (num--)
{ hugemul(reg1,2,TRUE);
hugeinc(reg1,TRUE);
}
}
/*
calculates fibonacci number
*/
void fibonacci(unsigned int *reg1,unsigned int num)
{ unsigned int reg2[MAXLEN+1],
reg3[MAXLEN+1],
*r2,
*r3,
*temp;
reg2[0]=0;
r2=reg2;
reg3[0]=0;
r3=reg3;
hugeinc(reg3,TRUE);
while (num--)
{ hugeadd(r2,r3,TRUE);
temp=r2;
r2=r3;
r3=temp;
}
hugeequ(reg1,r2);
}
/*
check for small factor, quick
*/
bool factor(unsigned int *reg1,unsigned int trial)
{ unsigned int carry;
hugemod(reg1,trial,&carry);
if(!carry)
{ hugediv(reg1,trial,&carry);
return TRUE;
}
return FALSE;
}
/*
removes small factors
quick on a DX2 for very large numbers
*/
void factorise(unsigned int *reg1)
{ unsigned int trial=1,
count=0,
res;
bool prime;
if(!reg1[0])return;
while(factor(reg1,2))count++;
if(count){ printf("Factor : 2");
if(count>1)printf(" ^ %u ",count);
printf("\n");
}
do
{ do
{ trial+=2;
res=3;
prime=TRUE;
while((res*res<=trial)&&(prime))
{ if(!(trial%res))prime=FALSE;
res+=2;
}
} while(!prime);
if(trial>1)
{ count=0;
while(factor(reg1,trial))count++;
if(count){ printf("Factor : %u",trial);
if(count>1)printf(" ^ %u",count);
printf("\n");
}
}
} while(trial!=1);
}
/*
converts buffer input to number for reg
*/
void hugeinp(unsigned int *reg1,char *buffer)
{ int count=0;
reg1[0]=0;
while(buffer[count])
{ hugemul(reg1,10,TRUE);
hugeaddnum(reg1,buffer[count++]-'0',TRUE);
}
}
/*
swaps two large numbers
*/
void hugeswap(unsigned int *reg1,unsigned int *reg2)
{ int t;
unsigned int tmp;
t=(reg1[0]>reg2[0]) ? reg1[0]:reg2[0];
while(t>=0)
{ tmp=reg1[t];
reg1[t]=reg2[t];
reg2[t--]=tmp;
}
}
/*
prints all regs to screen
*/
void hugepriregs(void)
{ printf("a = ");
hugepri(regA,FALSE);
printf("b = ");
hugepri(regB,FALSE);
printf("c = ");
hugepri(regC,FALSE);
printf("d = ");
hugepri(regD,FALSE);
}
/*
calculates gcd of two regs
*/
void hugegcd(unsigned int *reg1,unsigned int *reg2)
{ unsigned int work1[MAXLEN+1];
hugeequ(work1,reg2);
do
{ hugerdiv(reg1,work1,FALSE);
hugeswap(reg1,work1);
} while(work1[0]);
}
/*
calculates mprime value (or prime fac)
ie 3*5*7*11*13*... up to num
*/
void mprime(unsigned int *reg1,unsigned int num)
{ unsigned int count=0;
reg1[0]=0;
hugeinc(reg1,TRUE);
while((primes[count]<=num)&&(primes[count]))
hugemul(reg1,primes[count++],TRUE);
}
/*
squareroot - nice fast root extraction in binary
get the old schoolbooks out for this one
best to try it on pen and paper but it works.
*/
void hugeroot(unsigned int *reg1,unsigned int *reg2)
{ unsigned int quotient[MAXLEN+1];
unsigned int reg2byte,
bytecount,
lengthcount,
carry,
len1;
bool greater;
quotient[0]=reg1[0]=0;
lengthcount=reg2[0];
while(lengthcount)
{ reg2byte=reg2[lengthcount--];
for(bytecount=0;bytecount<8;bytecount++)
{ hugemul(quotient,4,TRUE);
hugeaddnum(quotient,reg2byte>>14,TRUE);
hugemul(reg1,4,TRUE);
if(quotient[0]>reg1[0])greater=TRUE;
else if(quotient[0]<reg1[0])greater=FALSE;
else { greater=FALSE;
len1=quotient[0];
do
{ if(quotient[len1]>reg1[len1])greater=TRUE;
} while((quotient[len1]==reg1[len1])&&(len1--));
}
if(greater) { hugersub(quotient,reg1);
hugedec(quotient);
hugeaddnum(reg1,2,TRUE);
}
hugediv2(reg1,&carry);
reg2byte<<=2;
}
}
}
/*
this is used in psptest,etc
it calculates reg1*reg2 mod reg3
this is what I meant earlier by large intermediate values
overflow will not occur but checking needs to be off
*/
void hugemulmod(unsigned int *reg1,unsigned int *reg2,unsigned int *reg3)
{ hugermul(reg1,reg2,FALSE);
hugerdiv(reg1,reg3,FALSE);
}
/*
heres the pseudoprime test
see any modern number theory book
a pseudoprime is not necessarily prime
*/
void psptest(unsigned int *reg1,unsigned int num)
{ unsigned int result[2*MAXLEN+1],
len1,
reg1byte,
bytecount;
result[0]=result[1]=1;
len1=reg1[0];
while(len1)
{ reg1byte=reg1[len1--];
for(bytecount=0;bytecount<16;bytecount++)
{ hugemulmod(result,result,reg1);
if(kbhit()) if(getch()=='e') return;
if(reg1byte>>15) { hugemul(result,num,FALSE);
hugerdiv(result,reg1,FALSE);
}
reg1byte<<=1;
}
}
if((result[0]==1)&&(result[1]==num)) printf("Pseudoprime\n\r");
else printf("Composite\n\r");
}
/*
heres pollards method of factorisation
use after removing small factors
factors produced will have to be tested for primeness
can give some good results
*/
void pollard(unsigned int *reg1,unsigned int num)
{ unsigned int test[2*MAXLEN+1],
wk1[2*MAXLEN+1],
loops;
int mulcount;
long count=3;
char ch;
bool gcdtest=TRUE;
test[0]=test[1]=1;
for(mulcount=0;mulcount<32;mulcount++)
hugemul(test,num,TRUE);
hugedec(test);
do
{ if(gcdtest)
{ hugeequ(wk1,reg1);
hugegcd(wk1,test);
if(!((wk1[0]==1)&&(wk1[1]==1)))
{ printf("Factor : ");
hugepri(wk1,FALSE);
hugerdiv(reg1,wk1,TRUE);
return;
}
}
if(kbhit()){ ch=getch();
if(ch=='e') return;
else if(ch=='o'){ if(gcdtest){ gcdtest=FALSE;
printf("gcd test off\n\r");
}
else { gcdtest=TRUE;
printf("gcd test on\n\r");
}
}
else printf("%lu\n\r",count);
}
wk1[0]=wk1[1]=1;
hugeinc(test,FALSE);
loops=31;
while(!(count&(1<<loops)))loops--;
for(mulcount=loops;mulcount>=0;mulcount--)
{ hugemulmod(wk1,wk1,reg1);
if(count&(1<<mulcount)) hugemulmod(wk1,test,reg1);
}
hugeequ(test,wk1);
hugedec(test);
if(count>1000)
do count+=2;
while((!(count%3))||(!(count%5))||(!(count%7))||(!(count%11))||(!(count%13)));
else if(count>100)count+=2;
else count++;
} while(count!=1);
printf("No factor found\n\r");
}
/*
performs psp test multiple times over primes<num
*/
void autopsptest(unsigned int *reg1,unsigned int num)
{ unsigned int count=0;
while((num>=primes[count])&&(primes[count]))
{ printf("%u - ",primes[count]);
psptest(reg1,primes[count++]);
}
}
/*
a montecarlo method of factorisation
crap it is too. any better ?
*/
void montecarlo(unsigned int *reg1,unsigned int num)
{ unsigned int test[2*MAXLEN+1],
count,
wk1[2*MAXLEN+1];
test[0]=count=1;
test[1]=num;
do
{ hugeequ(wk1,reg1);
hugegcd(wk1,test);
if (!((wk1[0]==1)&&(wk1[1]==1))){ printf("Factor : ");
hugepri(wk1,FALSE);
hugerdiv(reg1,wk1,TRUE);
return;
}
if(kbhit())if(getch()=='e')return;
else printf("%u\n\r",count);
hugemulmod(test,test,reg1);
hugeinc(test,TRUE);
randomize();
if(random(2)) hugeaddnum(test,random(50),TRUE);
count++;
} while(TRUE);
}
/*
the sequence method of factorisation or pollards rho method
could take some optimisation - see a text on advanced number
theory, or Riesels book on computer methods of factorisation
still works quite well but don't wait too long
*/
void sequence(unsigned int *reg1,unsigned int num)
{ unsigned int testu[2*MAXLEN+1],
testv[2*MAXLEN+1],
wk1[2*MAXLEN+1],
count=1;
testu[0]=testv[0]=1;
testu[1]=testv[1]=num;
do
{ hugemulmod(testu,testu,reg1);
hugemulmod(testv,testv,reg1);
hugeinc(testu,TRUE);
hugeinc(testv,TRUE);
hugemulmod(testv,testv,reg1);
hugeinc(testv,TRUE);
hugeequ(wk1,testu);
hugeadd(wk1,reg1,FALSE);
hugersub(wk1,testv);
hugegcd(wk1,reg1);
if(!((wk1[0]==1)&&(wk1[1]==1))){ printf("Factor : ");
hugepri(wk1,FALSE);
hugerdiv(reg1,wk1,TRUE);
return;
}
if(kbhit())if(getch()=='e')return;
else printf("%u\n\r",count);
count++;
} while(TRUE);
}
/*
heres an interesting one. This calculates num^reg1 mod reg2
*/
void powmod(unsigned int num,unsigned int *reg1,unsigned int *reg2)
{ unsigned int result[2*MAXLEN+1],
len1,
reg1byte,
bytecount;
result[0]=result[1]=1;
len1=reg1[0];
while(len1)
{ reg1byte=reg1[len1--];
for (bytecount=0;bytecount<16;bytecount++)
{ hugemulmod(result,result,reg2);
if(reg1byte>>15){ hugemul(result,num,FALSE);
hugerdiv(result,reg2,FALSE);
}
reg1byte<<=1;
}
}
hugeequ(reg1,result);
}
/*
witness was a bad phrase to use but these routines are used in
PROVING a number to be prime. See doc for details
*/
bool witnesstest(unsigned int *reg1,unsigned int *reg2,unsigned int num)
{ unsigned int power[2*MAXLEN+1];
hugeequ(power,reg1);
hugedec(power);
hugerdiv(power,reg2,TRUE);
powmod(num,power,reg1);
if(!((power[0]==1)&&(power[1]==1)))return TRUE;
return FALSE;
}
void witness(unsigned int *reg1,unsigned int *reg2,unsigned int num)
{ if(witnesstest(reg1,reg2,num))printf("Passed\n\r");
else printf("Failed\n\r");
}
void findwitness(unsigned int *reg1,unsigned int *reg2)
{ unsigned int i=0;
do
{ if(witnesstest(reg1,reg2,primes[i]))
{ printf("Witness %u - checking pseudoprime\n\r",primes[i]);
psptest(reg1,primes[i]);
return;
}
} while(primes[++i]);
printf("No witness found\n\r");
}
/*
this routine will do most of the work for you
it only stops if n-1 cannot immediately be factorised
for a large number
*/
void proveprime(unsigned int *reg1,unsigned int *reg2)
{ unsigned int trial=2,
count=0,
carry,
test[2*MAXLEN+1],
psps[256],
i;
bool table=TRUE,
done;
hugeequ(reg2,reg1);
hugedec(reg2);
for(i=0;i<256;i++)psps[i]=0;
do
{ hugemod(reg2,trial,&carry);
if(!carry)
{ while(!carry)
{ hugediv(reg2,trial,&carry);
hugemod(reg2,trial,&carry);
}
test[0]=1;
test[1]=trial;
printf("Factor : %u looking for witness\n\r",trial);
i=0;
done=FALSE;
do
{ if(witnesstest(reg1,test,primes[i]))
{ printf("Witness : %u checking pseudoprime\n\r",primes[i]);
if(psps[primes[i]]) printf("Pseudoprime\n\r");
else
{ hugeequ(test,reg1);
hugedec(test);
powmod(primes[i],test,reg1);
if((test[0]==1)&&(test[1]==1))
{ printf("Pseudoprime\n\r");
psps[primes[i]]=1;
}
else
{ printf("N is composite\n\r");
return;
}
}
done=TRUE;
}
} while((primes[++i])&&(!done));
if(!done)
{ printf("No witness found\n\r");
return;
}
}
if(table) trial=primes[++count];
if(!trial)
{ table=FALSE;
trial=primes[count-1];
}
if(!table)
{ do
{ count=0;
done=TRUE;
trial+=2;
do
{ if(!(trial%primes[count])) done=FALSE;
} while(primes[++count]);
} while(!done);
}
} while(trial!=1);
if(reg2[0]==2)
{ printf("Factor : ");
hugepri(reg2,TRUE);
printf(" looking for witness\n\r");
hugeequ(test,reg2);
i=0;
done=FALSE;
do
{ if(witnesstest(reg1,test,primes[i]))
{ printf("Witness : %u checking pseudoprime\n\r",primes[i]);
if(psps[primes[i]]) printf("Pseudoprime\n\r");
else
{ hugeequ(test,reg1);
hugedec(test);
powmod(primes[i],test,reg1);
if((test[0]==1)&&(test[1]==1))
{ printf("Pseudoprime\n\r");
psps[primes[i]]=1;
}
else
{ printf("N is composite\n\r");
return;
}
}
done=TRUE;
}
} while((primes[++i])&&(!done));
if(!done){ printf("No witness found\n\r");
return;
}
reg2[0]=reg2[1]=1;
}
if((reg2[0]==1)&&(reg2[1]==1)) printf("N is prime\n\r");
else
{ hugeequ(test,reg1);
hugedec(test);
hugerdiv(test,reg2,TRUE);
hugemul(test,256,FALSE);
hugemul(test,256,FALSE);
hugermul(test,test,FALSE);
done=FALSE;
if(test[0]>reg1[0])done=TRUE;
else if(test[0]==reg1[0])
{ i=test[0];
while((i)&&(!done))
{ if(test[i]>reg1[i]) done=TRUE;
else if(test[i]==reg1[i])i=1;
i--;
}
}
if(!done){ printf("Test unfinished - residue left to be checked\n\r");
return;
}
printf("Residue : ");
hugepri(reg2,TRUE);
printf(" looking for witness\n\r");
hugeequ(test,reg2);
i=0;
done=FALSE;
do
{ if(witnesstest(reg1,test,primes[i]))
{ printf("Witness : %u checking pseudoprime\n\r",primes[i]);
if(psps[primes[i]]) printf("Pseudoprime\n\r");
else
{ hugeequ(test,reg1);
hugedec(test);
powmod(primes[i],test,reg1);
if((test[0]==1)&&(test[1]==1))
{ printf("Pseudoprime\n\r");
psps[primes[i]]=1;
}
else
{ printf("N is composite\n\r");
return;
}
}
done=TRUE;
}
} while((primes[++i])&&(!done));
if(!done){ printf("Test unfinished - residue left to be checked\n\r");
return;
}
reg2[0]=reg2[1]=1;
printf("N is prime\n\r");
}
}
/*
calculates factorial
*/
void factorial(unsigned int *reg1,unsigned int num)
{ reg1[0]=0;
hugeinc(reg1,FALSE);
while(num>1) hugemul(reg1,num--,TRUE);
}
/*
calculates 2^reg1
*/
void power2(unsigned int *reg1,unsigned int num)
{ reg1[0]=0;
hugeinc(reg1,FALSE);
while(num--) hugemul2(reg1,TRUE);
}
/*
and this does num^reg1
*/
void pown(unsigned int *reg1,unsigned int num)
{ unsigned int test[2*MAXLEN+1];
test[0]=test[1]=1;
while(num--) hugermul(test,reg1,TRUE);
hugeequ(reg1,test);
}
/*
heres the old favourite fermats method of factorisation
a sieve is employed for speed with 20 values defined at the start
of the program.
Still seems a bit slow though or am I expecting too much
*/
void fermatsieve(unsigned int *reg1)
{ int i,
j,
calc;
bool done,
show;
unsigned int wk1[2*MAXLEN+1],
wk2[2*MAXLEN+1],
wk3[2*MAXLEN+1],
carry;
for(i=0;i<NUM_SIEVEVALUES;i++)
for(j=0;j<sievevalue[i];j++)
sieves[(i<<8)+j]=0;
for(i=0;i<NUM_SIEVEVALUES;i++)
for(j=0;j<sievevalue[i];j++)
{ calc=(j*j)%(sievevalue[i]);
sieves[(i<<8)+calc]|=256;
}
for(i=0;i<NUM_SIEVEVALUES;i++)
{ hugemod(reg1,sievevalue[i],&carry);
for(j=0;j<sievevalue[i];j++)
{ calc=(j*j-carry+sievevalue[i])%(sievevalue[i]);
if(sieves[(i<<8)+calc]&256)sieves[(i<<8)+j]|=1;
}
}
for(i=0;i<NUM_SIEVEVALUES;i++)
for(j=0;j<sievevalue[i];j++)
sieves[(i<<8)+j]&=1;
hugeroot(wk1,reg1);
hugeinc(wk1,FALSE);
for(i=0;i<NUM_SIEVEVALUES;i++)
hugemod(wk1,sievevalue[i],&modtable[i]);
show=FALSE;
for(;;)
{ done=FALSE;
i=0;
do
{ if(!(sieves[(i<<8)+modtable[i]])) done=TRUE;
} while((++i<NUM_SIEVEVALUES)&&(!done));
if(kbhit())if(getch()=='e')return;
else show=TRUE;
if(!done)
{ hugeequ(wk2,wk1);
hugermul(wk2,wk2,FALSE);
hugersub(wk2,reg1);
hugeroot(wk3,wk2);
hugeequ(wk2,wk1);
hugersub(wk2,wk3);
if(show){ hugepri(wk2,FALSE);
show=FALSE;
}
hugegcd(wk2,reg1);
if(!((wk2[0]==1)&&(wk2[1]==1)))
{ printf("Factor : ");
hugepri(wk2,FALSE);
hugerdiv(reg1,wk2,TRUE);
return;
}
}
hugeinc(wk1,FALSE);
for(i=0;i<NUM_SIEVEVALUES;i++)
if((++modtable[i])==sievevalue[i]) modtable[i]=0;
}
}
/*
heres the command interpreter
pretty basic , nuff said
*/
bool command(void)
{ bool cquit=FALSE;
int incount=0;
int bufptr=0;
int comptr=0;
unsigned int *regptr,*regptr2;
unsigned int tempreg[MAXLEN+1];
char ch;
char buffer[MAXLEN+30];
textcolor(CYAN);
cprintf("Command>");
textcolor(LIGHTGRAY);
_setcursortype(_NORMALCURSOR);
while(!cquit)
{ ch=getch();
if(ch==13){ cquit=TRUE;
buffer[incount]=0;
printf("\n\r");
}
else if((ch==8)&&(incount>0)){ incount--;
printf("%c %c",ch,ch);
}
else if((incount<MAXLEN+29)&&(ch>31)&&(ch<127)){ buffer[incount++]=ch;
printf("%c",ch);
}
}
_setcursortype(_NOCURSOR);
strlwr(buffer);
cquit=FALSE;
while(buffer[bufptr]==' ') bufptr++;
do
{ if(!strncmp(comtable[comptr].cmd,&buffer[bufptr],strlen(comtable[comptr].cmd)))
cquit=TRUE;
if(!cquit) comptr++;
} while((!cquit)&&(comtable[comptr].cmd!=NULL));
if(!cquit) { printf("Unknown Command\n\r");
return(TRUE);
}
else if(comtable[comptr].arg1==QUIT) return(FALSE);
bufptr+=strlen(comtable[comptr].cmd);
while(buffer[bufptr]==' ') bufptr++;
switch(comtable[comptr].arg1)
{ case REG: switch(buffer[bufptr])
{ case 'a': regptr=regA;
bufptr++;
break;
case 'b': regptr=regB;
bufptr++;
break;
case 'c': regptr=regC;
bufptr++;
break;
case 'd': regptr=regD;
bufptr++;
break;
default : printf("Unknown Register\n\r");
return(TRUE);
}
break;
case NIL: regptr=NULL;
break;
default: printf("Program Error\n\r");
exit(1);
}
while((buffer[bufptr]==',')||(buffer[bufptr]==' ')) bufptr++;
regptr2=NULL;
switch(comtable[comptr].arg2)
{ case CVALUE: switch(buffer[bufptr])
{ case 'a': regptr2=regA;
bufptr++;
break;
case 'b': regptr2=regB;
bufptr++;
break;
case 'c': regptr2=regC;
bufptr++;
break;
case 'd': regptr2=regD;
bufptr++;
break;
default : regptr2=tempreg;
incount=0;
if(!buffer[bufptr]){ printf("Too few arguments\n\r");
return(TRUE);
}
while((buffer[bufptr]>='0')&&(buffer[bufptr]<='9'))
buffer[incount++]=buffer[bufptr++];
buffer[incount]=0;
hugeinp(tempreg,buffer);
}
while(buffer[bufptr]==' ')bufptr++;
if(buffer[bufptr]){ printf("Too many arguments\n\r");
return(TRUE);
}
if(comtable[comptr].arg3==NIL)
(*comtable[comptr].fn)(regptr,regptr2);
else if(comtable[comptr].arg3==TVAL)
(*comtable[comptr].fn)(regptr,regptr2,TRUE);
else if(comtable[comptr].arg3==FVAL)
(*comtable[comptr].fn)(regptr,regptr2,FALSE);
else { printf("Program Error\n\r");
exit(1);
}
break;
case NUM : incount=0;
if(!buffer[bufptr]){ printf("Too few arguments\n\r");
return(TRUE);
}
while((buffer[bufptr]>='0')&&(buffer[bufptr]<='9'))
{ incount=incount*10+buffer[bufptr]-'0';
bufptr++;
}
while(buffer[bufptr]==' ') bufptr++;
if(buffer[bufptr]){ printf("Too many arguments\n\r");
return(TRUE);
}
if(comtable[comptr].arg3==NIL)
(*comtable[comptr].fn)(regptr,incount);
else { printf("Program Error\n\r");
exit(1);
}
break;
case NIL : if(comtable[comptr].arg1==NIL)
(*comtable[comptr].fn)();
else if(comtable[comptr].arg3==NIL)
(*comtable[comptr].fn)(regptr);
else if(comtable[comptr].arg3==TVAL)
(*comtable[comptr].fn)(regptr,TRUE);
else if(comtable[comptr].arg3==FVAL)
(*comtable[comptr].fn)(regptr,FALSE);
else { printf("Program Error\n\r");
exit(1);
}
break;
default : printf("Program Error\n\r");
exit(1);
}
return(TRUE);
}
/*
main routine
doesn't do a lot just loops
*/
int main(void)
{ init();
clrscr();
textcolor(RED);
cprintf("Multi-Precision Integer Maths Program v1.0\n\r");
cprintf("By Paul Young\n\r");
cprintf("Public Domain\n\r\n\r");
textcolor(LIGHTGRAY);
do
{} while (command());
_setcursortype(_NORMALCURSOR);
return(0);
}